﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Text;
using System.Threading.Tasks;

namespace Hotel.OTA.Service.Common.Utility
{
    /// <summary>
    /// 唯一码帮助类
    /// </summary>
    public static class UniqueIDHelper
    {
        /// <summary>
        /// 编码字符
        /// </summary>
        private static readonly string CharList = "123456789ABCDEFGHJKLMNPQRSTUVWXYZ";

        /// <summary>
        /// 新的GUID等效码
        /// </summary>
        /// <returns>压缩GUID等效码字符串</returns>
        public static string ShrinkGuid()
        {
            return ShrinkGuid(Guid.NewGuid());
        }

        /// <summary>
        /// 压缩已有的GUID
        /// </summary>
        /// <param name="target">GUID</param>
        /// <returns>压缩GUID等效码字符串</returns>
        public static string ShrinkGuid(Guid target)
        {
            return Encode(target.ToByteArray());
        }

        /// <summary>
        /// 解码缩短的GUID
        /// </summary>
        /// <param name="target">压缩GUID等效码字符串</param>
        /// <returns>GUID</returns>
        public static Guid ToGuid(string target)
        {
            Guid result = Guid.Empty;
            if ((!string.IsNullOrEmpty(target)))
            {
                try
                {
                    byte[] data = Decode(target);
                    result = new Guid(data);
                }
                catch (FormatException)
                {
                }
            }

            return result;
        }

        /// <summary>
        /// 加密
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        private static string Encode(byte[] data)
        {
            if (data == null || data.Length <= 0)
            {
                throw new ArgumentException("输入的参数不能为空。");
            }

            // 转换 byte[] 为 BigInteger
            BigInteger intData = 0;
            for (int i = 0; i < data.Length; i++)
            {
                intData = intData * 256 + data[i];
            }

            // 转换 BigInteger 为 string
            string result = "";
            while (intData > 0)
            {
                int remainder = (int)(intData % 33);
                intData /= 33;
                result = CharList[remainder] + result;
            }

            // Append `1` for each leading 0 byte
            for (int i = 0; i < data.Length && data[i] == 0; i++)
            {
                result = '1' + result;
            }

            return result;
        }

        /// <summary>
        /// 解密
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        private static byte[] Decode(string input)
        {
            if (String.IsNullOrWhiteSpace(input))
            {
                throw new ArgumentException("输入的参数不能为空。");
            }

            // 解码 string 为 BigInteger 
            BigInteger intData = 0;
            for (int i = 0; i < input.Length; i++)
            {
                int digit = CharList.IndexOf(input[i]); //Slow
                if (digit < 0)
                {
                    throw new FormatException(string.Format("Invalid character `{0}` at position {1}", input[i], i));
                }

                intData = intData * 33 + digit;
            }

            // 转换 BigInteger 为 byte[]
            // Leading zero bytes get encoded as leading `1` characters
            int leadingZeroCount = input.TakeWhile(c => c == '1').Count();
            var leadingZeros = Enumerable.Repeat((byte)0, leadingZeroCount);
            var bytesWithoutLeadingZeros =
                intData.ToByteArray()
                .Reverse()// to big endian
                .SkipWhile(b => b == 0);//strip sign byte
            var result = leadingZeros.Concat(bytesWithoutLeadingZeros).ToArray();
            return result;
        }
    }
}
